<?php
namespace Tiger;

class Worker
{
	/**
	 * 版本号
	 * @var string
	 */
	const VERSION = '1.0.0';
	
	/**
	 * 多协议worker
	 * @var array
	 */
	protected static $_workers = array();
	
	/**
	 * Socket name. 例如：http://0.0.0.0:80
	 * @var string
	 */
	protected $_socketName = '';
	
	/**
	 * 服务器参数设置
	 * @var array
	 */
	protected $_setting = array(
		'worker_num' => 1,
		'backlog'    => 1024,
	);
		
	/**
	 * 当前worker实例Id
	 * @var string
	 */
	protected $_workerId = '';
	
	/**
	 * 子进程pid组
	 */
	protected static $_pidMap = array();
	
	/**
	 * pid文件
	 */
	public static $pidFile = '';
	
	/**
	 * 启动文件
	 * @var string
	 */
	protected static $_startFile = '';
	
	/**
	 * log文件
	 */
	public static $logFile = '';
	
	/**
	 * 运行模式
	 * @var bool
	 */
	public static $daemonize = false;
	
	/**
	 * 应用层协议
	 */
	public $protocol = '';
	
	/**
	 * 传输协议
	 */
	public $transport = SWOOLE_SOCK_TCP;
	
	/**
	 * 是否启用ssl
	 * @var 
	 */
	public $ssl = false;
	
	/**
	 * 运行的进程数
	 * @var int
	 */
	public $count = 1;
	
	/**
	 * task进程数
	 */
	public $taskCount = 0;
	
	/**
	 * worker启动回调
	 * @var callback
	 */
	public $onWorkerStart = null;
	
	/**
	 * swoole process 对象
	 */
	public $swooleProcess = array();
	
	/**
	 * swoole 内置协议
	 * @var array
	 */
	protected static $_swooleProtocol = array(
		'http'
	);
	
	/**
	 * 
	 * @var 
	 */
	protected static $_builtinTransports = array(
		'tcp'   => array('type' => SWOOLE_SOCK_TCP, 'ssl' => false),
		'udp'   => array('type' => SWOOLE_SOCK_UDP, 'ssl' => false),
		'ssl'   => array('type' => SWOOLE_SOCK_TCP, 'ssl' => true),
		'sslv2' => array('type' => SWOOLE_SOCK_TCP, 'ssl' => true),
		'sslv3' => array('type' => SWOOLE_SOCK_TCP, 'ssl' => true),
		'tls'   => array('type' => SWOOLE_SOCK_TCP, 'ssl' => true)
	);
	
	/**
	 * 应用根目录.
	 *
	 * @var string
	 */
	protected $_autoloadRootPath = '';
	
		
	public function __construct($socket_name = '', $option = array())
	{
		if (!empty(self::$_worker))
			return ;
		//清除worker_num和task_worker_num的设置
		if (isset($option['worker_num']))
			unset($option['worker_num']);
		if (isset($option['task_worker_num'])) 
			unset($option['task_worker_num']);
		
		//保存当前实例
		$this->_workerId = spl_object_hash($this);
		self::$_workers  = $this;
		self::$_pidMap   = array();
		
		//应用根目录
		$backtrace                = debug_backtrace();
		$this->_autoloadRootPath  = dirname($backtrace[0]['file']);
		
		if (!empty($socket_name))
			$this->_socketName = $socket_name;
		
	}
	
	/**
	 * 环境检查
	 */
	protected static function checkEvn()
	{
		// Only for cli.
		if (php_sapi_name() != "cli") 
		{
			exit("only run in command line mode \n");
		}
		// Check swoole
		if (!extension_loaded('swoole')) 
		{
			exit("check extension swoole has install or loaded \n");
		}
	}
	
	/**
	 * 初始化
	 */
	protected static function init()
	{
		// 启动文件
		$backtrace        = debug_backtrace();
		self::$_startFile = $backtrace[count($backtrace) - 1]['file'];
		
		// Pid文件
		if (empty(self::$pidFile)) 
		{
			self::$pidFile = realpath(__DIR__ . "/../" . str_replace('/', '@', self::$_startFile) . ".pid");
		}
		
		//log文件
		if (empty(self::$logFile)) 
		{
			self::$logFile = realpath(__DIR__ . '/../tiger.log');
		}
		touch(self::$logFile);
		chmod(self::$logFile, 0622);
	}
	
	/**
	 * 参数解析
	 */
	protected static function parseCommand()
	{
		global $argv;
		
		$start_file = $argv[0];
		if (!isset($argv[1])) 
		{
			exit("Usage: php start_file.php {start|stop|restart|reload|status}\n");
		}
		
		$command  = trim($argv[1]);
		$command2 = isset($argv[2]) ? $argv[2] : '';
		if ($command2 === '-d')
		{
			self::$daemonize = true;
		}
		
		$master_pid      = @file_get_contents(self::$pidFile);
		$master_is_alive = $master_pid && @posix_kill($master_pid, 0);
		
		if ($master_is_alive) 
		{
			if ($command === 'start' && posix_getpid() != $master_pid) 
			{
				self::log("Tiger [$start_file] already running");
				exit;
			}
		} 
		else if($command !== 'start' && $command !== 'restart') 
		{
			self::log("Tiger [$start_file] not run");
			exit;
		}
		
		switch ($command)
		{
			case 'start':
				break;
			case 'status':
// 				if (is_file(self::$_statisticsFile)) 
// 				{
// 					@unlink(self::$_statisticsFile);
// 				}
// 				// Master process will send status signal to all child processes.
// 				posix_kill($master_pid, SIGUSR2);
// 				// Waiting amoment.
// 				usleep(500000);
// 				// Display statisitcs data from a disk file.
// 				@readfile(self::$_statisticsFile);
				exit(0);
			case 'restart':
			case 'stop':
				self::log("Tiger [$start_file] is stoping ...");
				//发送服务关闭信号.
				$master_pid && posix_kill($master_pid, SIGTERM);
				//超时时间.
				$timeout    = 10;
				$start_time = time();
				while (1) 
				{
					$master_is_alive = $master_pid && posix_kill($master_pid, 0);
					if ($master_is_alive) 
					{
						if (time() - $start_time >= $timeout) 
						{
							self::log("Tiger [$start_file] stop fail");
							exit;
						}
						usleep(10000);
						continue;
					}
					//success.
					self::log("Tiger [$start_file] stop success");
					if ($command === 'stop') 
					{
						exit(0);
					}
					break;
				}
				break;
			case 'reload':
				posix_kill($master_pid, SIGUSR1);
				self::log("Tiger [$start_file] reload");
				exit;
			default :
				exit("Usage: php start_file.php {start|stop|restart|reload|status}\n");			
		}
		
	}
	
	/**
	 * 初始化所有worker实例
	 */
	protected static function initWorkers()
	{
		$protocol = array();
		$_worker = self::$_workers;
		if (!empty($_worker)) 
		{
			$protocol = $_worker->parseUseProtocol();
			print_r($protocol);
		}
	}
	
	/**
	 * 创建swoole进程
	 */
	protected function createProcess()
	{
		if (!is_callable($this->onWorkerStart)) 
		{
			throw new \Exception("onWorkerStart is not callable");
		}
		for ($i = 0; $i < $this->count; $i++)
		{
			$process = new \swoole_process($this->onWorkerStart);
			$this->swooleProcess[$i] = $process;
		}
	}
	/**
	 * 运行实例
	 */
	protected function run()
	{
		if (!empty($this->swooleProcess)) 
		{
			foreach ($this->swooleProcess as $i => $process)
			{
				$pid = $process->start();
				self::$_pidMap[$this->_workerId][$i] = $pid;
			}
		}
	}
	
	/**
	 * 解析使用协议
	 */
	protected function parseUseProtocol()
	{
		if (!$this->_socketName) 
		{
			return array();
		}
		$local_socket = $this->_socketName;
		$useSwooleProtocol = '';
		
		list($scheme, $address, $port) = explode(':', $this->_socketName, 3);
		$address = trim($address,'/');
		
		if (!isset(self::$_builtinTransports[$scheme])) 
		{
			$_scheme = strtolower($scheme);
			if (in_array($_scheme, self::$_swooleProtocol)) 
			{
				$useSwooleProtocol = $_scheme;
			}
			else if (class_exists($scheme)) 
			{
				$this->protocol = $scheme;
			}
			else 
			{
				$scheme         = ucfirst($scheme);
				$this->protocol = '\\Protocols\\' . $scheme;
				if (!class_exists($this->protocol)) 
				{
					$this->protocol = "\\Tiger\\Protocols\\$scheme";
					if (!class_exists($this->protocol)) 
					{
						throw new \Exception("class \\Protocols\\$scheme not exist");
					}
				}				
			}
		}
		else 
		{
			$this->transport = self::$_builtinTransports[$scheme]['type'];
			$this->ssl = self::$_builtinTransports[$scheme]['ssl'];
		}
		return array(
			'host' => $address,
			'port' => empty($port) ? 80 : $port,
			'useSwoole' => $useSwooleProtocol
		);
		
	}
	/**
	 * 运行所有实例
	 */
	public static function runAll()
	{
		self::checkEvn();
		self::init();
		self::parseCommand();
		self::initWorkers();
	
	}
	
	/**
	 * Log日志.
	 *
	 */
	public static function log($msg)
	{
		$msg = $msg . "\n";
		if (!self::$daemonize) 
		{
			self::safeEcho($msg);
		}
		file_put_contents(self::$logFile, date('Y-m-d H:i:s') . ' ' . 'pid:'. posix_getpid() . ' ' . $msg, FILE_APPEND | LOCK_EX);
	}
	
	/**
	 * 安全 Echo.
	 * @param $msg
	 */
	public static function safeEcho($msg)
	{
		if (!function_exists('posix_isatty') || posix_isatty(STDOUT)) 
		{
			echo $msg;
		}
	}
	
	
}